// CylonOptometry.c
// Joe Pardue September 16, 2008

#include <avr/io.h>
#define F_CPU 1000000UL
#include <util/delay.h>
#include <stdlib.h>

// Function declarations
void initialize(void);
uint8_t dillyDally(void);
void cylonEyes(void);
void cylonEyes2(void);
void cylonEyes3(void);
void wallEyes(void);
void antEyes(void);
void vibroEyes(void);
void blinkinEyes(void);
void randomEyes(void);
void errorEyes(void);

// LED pattern function selection numbers
#define CYLONEYES	0x00 // 000 - cylonEyes
#define CYLONEYES2	0x01 // 001 - cylonEyes2
#define CYLONEYES3	0x02 // 010 - cylonEyes3
#define WALLEYES	0x03 // 011 - wallEyes
#define ANTEYES 	0x04 // 100 - antEyes
#define VIBROEYES 	0x05 // 101 - vibroEyes
#define BLINKINEYES 0x06 // 110 - blinkinEyes
#define RANDOMEYES 	0x07 // 111 - randomEyes

// DIP switch masks
#define POLARITYMASK 	0x01	// 00000001
#define SELECTMASK 		0x0E	// 00001110
#define SPEEDMASK 		0xF0	// 11110000

// macro to clear all bits except those 
// set to 1 in the mask
#define maskBit(p,m) (p & m)

// Global variables
uint8_t volatile SweepSelect = 0; // bits 1,2, and 3 of DipSwitch
uint8_t volatile Polarity = 1;    // bit 0 of DipSwitch

int main (void)
{
	DDRB = 0x00;  // set port B for input
	PORTB = 0xFF; // enable pull up resistors on input port
	DDRD = 0xFF;  // set port D for output

	dillyDally(); // sets up selections

	while(1)
	{
		switch (SweepSelect)
		{
			case CYLONEYES:
				cylonEyes();
				break;
			case CYLONEYES2:
				cylonEyes2();
				break;
			case CYLONEYES3:
				cylonEyes3();
				break;
			case WALLEYES:
				wallEyes();
				break;
			case ANTEYES:
				antEyes();				
				break;
			case VIBROEYES:
				vibroEyes();
				break;
			case BLINKINEYES:
				blinkinEyes();
				break;			
			case RANDOMEYES:
				randomEyes();
				break;				
			default:
				errorEyes();
				break;
		}
	}
}

// waits for 50 x milliseconds specified in SweepSpeed
// returns 0 if DipSwitch has changed
// otherwise returns 0
uint8_t dillyDally()
{
	uint8_t static DipSwitch; // state of all the bits
	uint8_t static SweepSpeed; // bits 4,5,6, and 7 of DipSwitch

	// declare and initialize the scroll delay_count
	uint32_t delay_count = 0;

	// load value
	DipSwitch = PINB;

	// load the delay count from the switch
	delay_count = (uint32_t)SweepSpeed;
	delay_count *= 50;

	// wait around for a while
	_delay_ms(delay_count);

	// check the switch to see if it has changed
	if( DipSwitch != PINB )
	{
		// polarity
		if(maskBit(PINB,POLARITYMASK)) Polarity = 1;
		else Polarity = 0;

		// mask off sweep selection
		SweepSelect = maskBit(PINB,SELECTMASK);
		SweepSelect = (SweepSelect >> 1);

		// mask off speed
		SweepSpeed = maskBit(PINB,SPEEDMASK);
		SweepSpeed = (SweepSpeed >> 4);

		// load new value
		DipSwitch = PINB;

		// it has changed so inform caller to bail out
		return 1;
	}
	return 0;
}

/*
00000001 == 0x01
00000010 == 0x02
00000100 == 0x04
00001000 == 0x08
00010000 == 0x10
00100000 == 0x20
01000000 == 0x40
10000000 == 0x80
01000000 == 0x40
00100000 == 0x20
00010000 == 0x10
00001000 == 0x08
00000100 == 0x04
00000010 == 0x02
*/
void cylonEyes()
{
	uint8_t i = 0;
	uint8_t ce[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };

	while(1)
	{
		// run up the array
		for(i = 0; i <= 7; i++)
		{
			if(dillyDally()) return; 	// delay or bail out
			if(Polarity) PORTD = ce[i]; // show non-inverted
			else PORTD = ~ce[i]; 		// show inverted
		}
		// run down the array
		for(i = 6; i >= 1; i--)
		{
			if(dillyDally()) return; // delay or bail out
			if(Polarity) PORTD = ce[i]; // show non-inverted
			else PORTD = ~ce[i]; 		// show inverted
		}
	}
}
/*
cylonEyes2
00000011 == 0x03
00000110 == 0x06
00001100 == 0x0C
00011000 == 0x18
00110000 == 0x30
01100000 == 0x60
11000000 == 0xC0
01100000 == 0x60
00110000 == 0x30
00011000 == 0x18
00001100 == 0x0C
00000110 == 0x06
00000011 == 0x03
*/
void cylonEyes2()
{
	uint8_t i = 0;
	uint8_t ce2[] = { 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0 };

	while(1)
	{
		// run up the array
		for(i = 0; i <= 6; i++)
		{
			if(dillyDally()) return; 	 // delay or bail out
			if(Polarity) PORTD = ce2[i]; // show non-inverted
			else PORTD = ~ce2[i]; 		 // show inverted
		}
		// run down the array
		for(i = 5; i >= 1; i--)
		{
			if(dillyDally()) return; 	 // delay or bail out
			if(Polarity) PORTD = ce2[i]; // show non-inverted
			else PORTD = ~ce2[i]; 		 // show inverted
		}
	}
}

/*
cylonEyes3
00000111 == 0x07
00001110 == 0x0E
00011100 == 0x1C
00111000 == 0x38
01110000 == 0x70
11100000 == 0xE0
01110000 == 0x70
00111000 == 0x31
00011100 == 0x1C
00001110 == 0x0E
00000111 == 0x07
*/
void cylonEyes3()
{
	uint8_t i = 0;
	uint8_t ce3[] = { 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0 };

	while(1)
	{
		// run up the array
		for(i = 0; i <= 5; i++)
		{
			if(dillyDally()) return; 	 // delay or bail out
			if(Polarity) PORTD = ce3[i]; // show non-inverted
			else PORTD = ~ce3[i]; 		 // show inverted
		}
		// run down the array
		for(i = 4; i >= 1; i--)
		{
			if(dillyDally()) return; 	 // delay or bail out
			if(Polarity) PORTD = ce3[i]; // show non-inverted
			else PORTD = ~ce3[i]; 		 // show inverted
		}
	}
}

/*
wallEyes
00000000 == 0x00
00011000 == 0x18
00100100 == 0x24
01000010 == 0x42
10000001 == 0x81
01000010 == 0x42
00100100 == 0x24
00011000 == 0x18
*/
void wallEyes()
{
	uint8_t i = 0;
	uint8_t we[] = { 0x00, 0x18, 0x24, 0x42, 0x81 };

	while(1)
	{
		// run up the array
		for(i = 0; i <= 4; i++)
		{
			if(dillyDally()) return; 	// delay or bail out
			if(Polarity) PORTD = we[i]; // show non-inverted
			else PORTD = ~we[i]; 		// show inverted
		}
		// run down the array
		for(i = 3; i >= 1; i--)
		{
			if(dillyDally()) return; 	// delay or bail out
			if(Polarity) PORTD = we[i]; // show non-inverted
			else PORTD = ~we[i]; 		// show inverted
		}
	}
}

/*
antEyes
01001001 == 0x49
10010010 == 0x92
00100100 == 0x24
*/
void antEyes()
{
	uint8_t i = 0;
	uint8_t ae[] = { 0x049, 0x92, 0x24 };

	while(1)
	{
		// loop thru the array
		for(i = 0; i <= 2; i++)
		{
			if(dillyDally()) return; 	// delay or bail out
			if(Polarity) PORTD = ae[i]; // show non-inverted
			else PORTD = ~ae[i]; 		// show inverted
		}
	}
}

// Notice that Polarity doesn't matter for the next three patterns

void vibroEyes()
{
	while(1)
	{
		if(dillyDally()) return; 	// delay or bail out
		PORTD = 0xAA; // 10101010
		if(dillyDally()) return; 	// delay or bail out
		PORTD = 0x55; // 01010101
	}
}

void blinkinEyes()
{
	while(1)
	{
		if(dillyDally()) return; 	// delay or bail out
		PORTD = 0x00; // 00000000
		if(dillyDally()) return; 	// delay or bail out
		PORTD = 0xFF; // 11111111
	}
}

void randomEyes()
{
	while(1)
	{
		if(dillyDally()) return; 	// delay or bail out
		PORTD = rand();
	}
}

// no movement, just stares at you till you fix the error
// you won't see this, but I saw it a lot during development
void errorEyes()
{
	while(1)
	{
		PORTD = 0x18; 				// 00011000 show error state
		if(dillyDally()) return; 	// delay or bail out
	}
}


